
#include <vector>
#include <list>
#include <mutex>
#include <condition_variable>
#include <iostream>
#include <chrono>
#include <queue>
#include <functional>
using namespace std;

#ifndef SYNC_QUEUE_5_HPP
#define SYNC_QUEUE_5_HPP
namespace tulun
{
    using Task = std::function<void(void)>;
    struct PairTask
    {
        size_t first;
        Task second;

    public:
        PairTask() : first(0), second(nullptr) {}
        PairTask(const size_t &tp, const Task &s)
            : first(tp), second(s)
        {
        }
        operator size_t() const { return first; }
        ~PairTask()
        {
            cout << "Destory PairTask " << endl;
        }
    };
    class SyncQueue
    {
    private:
        std::priority_queue<PairTask, std::vector<PairTask>, std::greater<PairTask>> m_taskQueues;
        size_t m_maxSize;
        mutable std::mutex m_mutex;
        std::condition_variable m_notEmpty;
        std::condition_variable m_notFull;
        std::condition_variable m_condition_;
        size_t m_waitTime; // 等待时间，单位为毫秒
        bool m_needStop;   // 标志位，用于表示队列是否需要停止

        bool IsFull() const
        {
            bool full = m_taskQueues.size() >= m_maxSize;
            if (full)
            {
                // clog << "m_queue 已经满了，需要等待..." << endl;
            }
            return full;
        }
        bool IsEmpty() const
        {
            bool empty = m_taskQueues.empty();
            if (empty)
            {
                // clog << "m_queue 已经空了，需要等待..." << endl;
            }
            return empty;
        }
        int Add(const PairTask &task)
        {
            std::unique_lock<std::mutex> locker(m_mutex);
            bool waitret = m_notFull.wait_for(locker, std::chrono::seconds(m_waitTime),
                                              [=,this]
                                              { return m_needStop || IsFull(); });
            if (!waitret)
            {
                return 1;
            }
            if (m_needStop)
            {
                return 2;
            }
            m_taskQueues.push(task);
            m_notEmpty.notify_all();
            return 0;
        }

    public:
        SyncQueue(int bucketSize, int maxsize = 200, size_t timeout = 1)
            : m_maxSize(maxsize),
              m_needStop(false),
              m_waitTime(timeout)
        {
        }
        ~SyncQueue()
        {
        }
        int Put(const PairTask &task)
        {
            return Add(task);
        }

        int Take(PairTask &task)
        {
            std::unique_lock<std::mutex> locker(m_mutex);
            while (IsEmpty() && !m_needStop)
            {
                m_notEmpty.wait(locker);
            }
            if (m_needStop)
                return 2;
            task = m_taskQueues.top();
            m_taskQueues.pop();
            while (std::cv_status::timeout != m_notEmpty.wait_for(locker, std::chrono::seconds(task.first)))
                ;
            m_notFull.notify_all();
            return 0;
        }
        void Stop()
        {
            std::unique_lock<std::mutex> locker(m_mutex);
            while (!m_needStop && !IsEmpty())
            {
                m_notFull.wait(locker);
            }
            m_needStop = true;
            m_notEmpty.notify_all();
            m_notFull.notify_all();
        }

        bool Empty() const
        {
            std::unique_lock<std::mutex> locker(m_mutex);
            return m_taskQueues.empty();
        }
        bool Full() const
        {
            std::unique_lock<std::mutex> locker(m_mutex);
            return m_taskQueues.size() >= m_maxSize;
        }
        size_t Size() const
        {
            std::unique_lock<std::mutex> locker(m_mutex);
            return m_taskQueues.size();
        }
        size_t Count() const
        {
            return m_taskQueues.size();
        }
    };
} // namespace tulun

#endif